package lib;

import static util.Constant.FILE_ITEMLISTS;
import static util.Constant.PATH_DATA;
import static util.Constant.STR_NAME_NULL;
import static util.Tool.getMaxID;
import io.InOutput;

import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;

import util.Comparator;
import base.Itemlist;
import base.User;
import base.items.Item;

/**
 * The ItemlistManager {@code class}. Manage the ItemLists
 * 
 * @author Peter NGO, Guillaume POUSSEL and Mathieu RUL
 * @version 1.0
 */
public class ItemlistManager {

	/**
	 * The {@code ItemlistManager} instance.
	 */
	private static ItemlistManager managerInstance;

	/**
	 * Get an instance of {@code ItemlistManager}.
	 * 
	 * @return an instance of {@code ItemlistManager}.
	 */
	public static ItemlistManager getInstance() {
		if (managerInstance == null) {
			managerInstance = new ItemlistManager();
		}
		return managerInstance;
	}

	/**
	 * The {@code Hashtable} containing the Itemlist object.
	 */
	private Hashtable<Integer, Object> itemlistTable;

	/**
	 * The {@code String} containing the path of Itemlist data.
	 */
	private String path = PATH_DATA + FILE_ITEMLISTS;

	/**
	 * Constructor of the {@code class}. Create the user manager.
	 */
	private ItemlistManager() {
		initialize();
		try {
			load();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Add an item to a list.
	 * 
	 * @throws Exception
	 */
	public boolean addItem(Itemlist list, Item item) throws Exception {
		return list.add(item.getID());
	}

	/**
	 * Create a new Itemlist.
	 * 
	 * @param name
	 *            the Itemlist name.
	 * 
	 * @return Integer the ID of created itemlist.
	 * 
	 * @throws IllegalArgumentException
	 */
	public Itemlist create(String name) {
		if (name == null || name.trim().isEmpty())
			throw new IllegalArgumentException(STR_NAME_NULL);
		Integer ID = getMaxID(itemlistTable) + 1;
		Itemlist itemlist = new Itemlist(ID, name, new HashSet<Integer>());
		try {
			UserManager.getInstance().addItemlist(ID);
		} catch (Exception e) {
			e.printStackTrace();
		}
		itemlistTable.put(ID, itemlist);
		save();
		return itemlist;
	}

	/**
	 * Get an itemlist with its ID
	 * 
	 * @param ID
	 *            the tag ID
	 */
	public Itemlist get(Integer ID) {
		return (itemlistTable.get(ID) == null ? null : (Itemlist) itemlistTable
				.get(ID));

	}

	public Set<Itemlist> getAll() {
		return this.getAll(itemlistTable.keySet());
	}

	public Set<Itemlist> getAll(Set<Integer> itemlistIDs) {
		Set<Itemlist> itemlists = new HashSet<Itemlist>();
		for (Integer itemlistID : itemlistIDs) {
			itemlists.add(get(itemlistID));
		}
		return itemlists;
	}

	public Set<Itemlist> getFromUsers(Set<User> users) {
		Set<Itemlist> itemlists = new HashSet<Itemlist>();
		for (User u : users) {
			itemlists.addAll(getAll(u.getItemLists()));
		}
		return itemlists;
	}

	/**
	 * Initialize the instance.
	 */
	public void initialize() {
		itemlistTable = new Hashtable<Integer, Object>();
	}

	/**
	 * Load the database in itemList table.
	 * 
	 * @throws Exception
	 */
	private void load() throws Exception {
		itemlistTable = InOutput.read(path);
	}

	/**
	 * Remove an Itemlist.
	 * 
	 * @param ID
	 *            the itemlist ID.
	 */
	public Itemlist remove(Integer ID) {
		Itemlist retour = (Itemlist) itemlistTable.remove(ID);
		for (Integer itemID : retour.getItems()) {
			ItemManager.getInstance().remove(itemID);
		}
		save();
		return retour;
	}

	/**
	 * Remove an item from a list.
	 * 
	 * @throws Exception
	 */
	public boolean removeItem(Itemlist list, Item item) throws Exception {
		return list.remove(item.getID());
	}

	/**
	 * Save the user itemList in database.
	 */
	public void save() {
		InOutput.write(itemlistTable, path);
	}

	/**
	 * Search an itemlist with its name
	 * 
	 * @param name
	 *            the tag Name
	 * @throws Exception
	 */
	public Itemlist[] searchByName(String name) throws Exception {
		for (Object itemlistObj : itemlistTable.values()) {
			Itemlist itemlist = (Itemlist) itemlistObj;
			if (itemlist.getName().equals(name))
				return new Itemlist[] { itemlist };
		}

		Set<Itemlist> itemlists = new HashSet<Itemlist>();
		for (Object itemlistObj : itemlistTable.values()) {
			Itemlist itemlist = (Itemlist) itemlistObj;
			if (Comparator.compare(itemlist.getName(), name))
				itemlists.add(itemlist);
		}

		return itemlists.toArray(new Itemlist[itemlists.size()]);
	}

	/**
	 * Set the path.
	 * 
	 * @param path
	 *            the path to set.
	 */
	public void setPath(String path) {
		this.path = path;
	}
}
